﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Xml;

using KELT;
using KELT.KELTObjects.LibraryObjectModel;
using KELT.KELTObjects.ViewportObjectModel;
using KELT.ErrorControl;
using KELT.Animation.Animation2D;
using KELT.Animation.ParticleEffect;

namespace KELT.Viewport
{
    public class ViewPortMgr : INotifyPropertyChanged
    {
        #region param
        private TOOL mainContext;
        private static ViewPortMgr instance;

        private static int m_INDEXNUMBER = 0;
        public int INDEXNUMBER
        {
            get
            {
                return ++m_INDEXNUMBER;
            }
        }


        private ViewportObj _currentSelectObj = null;

        public ViewportObj CurrentSelectObj
        {
            get { 
                return _currentSelectObj; 
            }
            set
            {
                _currentSelectObj = value;
                NotifyPropertyChanged("CurrentSelectObj");
            }
        }

        public Storyboard myStoryboard;
        #endregion

        public ViewPortMgr()
        {
            instance = this;
            m_rootObject = new GroupObject();
            myStoryboard = new Storyboard();

            myStoryboard.CurrentTimeInvalidated += myStoryboard_Changed;
            myStoryboard.Completed += myStoryboard_Completed;
        }

        public void SetMainContext(TOOL mainContext)
        {
            this.mainContext = mainContext;
        }


        private static ObservableCollection<ViewportObj> m_SelectList = new ObservableCollection<ViewportObj>();       // 텍스트 객체 저장 list
        public ObservableCollection<ViewportObj> selectList
        {
            get { return m_SelectList; }
            set { m_SelectList = value; }
        }

        private int m_mainTimeBarWidth = 1500;

        #region GET/SET
        public int MainTimeBarWidth
        {
            get
            {
                return m_mainTimeBarWidth;
            }

            set
            {
                m_mainTimeBarWidth = value;
                NotifyPropertyChanged("MainTimeBarWidth");
            }
        }

        #endregion

        #region obj
        private GroupObject m_rootObject;

        public ObservableCollection<ViewportObj> ObjectList
        {
            get { return m_rootObject.ObjectList; }
        }
        #endregion

        #region CreateObject
        public void CreateParticleObject(string str, double x, double y, double start, double end, int option)
        {
            int count = str.Length;

            int yLength = 0;
            int xTextCount = 0;
            for (int i = 0; i < count; i++)
            {
                char temp = str.ElementAt(i);
                if (str.ElementAt(i) == '\n')
                {
                    yLength += 50;
                    xTextCount = 0;
                    continue;
                }
                ParticleObject testText = new ParticleObject(mainContext, x + (xTextCount * 60), y + yLength, "" + str.ElementAt(i));
                xTextCount++;

                testText.setAnimationTime(myStoryboard, (start), end);
                testText.setFontFamily("HY각헤드라인M");
                
                TextObj textObj = new TextObj();//<수정필요
                textObj.addViewportObject(testText);
                testText.setLibraryObj(textObj);
                testText.setObjectIDX();

                IAnimation particleAnimation;
                switch(option)
                {
                    case 0 :
                        particleAnimation = new ParticleSpreadAnimation();
                        break;
                    case 1:
                        particleAnimation = new ParticleRotateAnimation();

                        particleAnimation.startTime = i/10 ;
                        particleAnimation.endTime = i/10+  1;
                        break;
                    case 2:
                        particleAnimation = new ParticleRainAnimation();

                        particleAnimation.startTime = i / 10.0;
                        particleAnimation.endTime = i / 10.0 + 0.1;
                        break;
                    case 3:
                        particleAnimation = new ParticleWindAnimation();

                        particleAnimation.startTime = xTextCount;
                        particleAnimation.endTime = xTextCount + 0.1;
                        break;
                    default:
                        particleAnimation = new ParticleSpreadAnimation();
                        break;
                }

                testText.AnimationRegist(particleAnimation, myStoryboard);

                Random rand = new Random();
                Color randomColor = Colors.White;
                if (mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).fontColor != null)
                {
                    int num = rand.Next(5);
                    while (num == mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).selectNum)
                    {
                        num = rand.Next(5);
                    }
                    randomColor = mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).fontColor[num];
                }

                testText.setColor(randomColor);


                m_rootObject.addObject(testText);

            }

        }

        public void CreateGroupText(IList<KELT_OBJ> list, double x, double y, double start, double end, int option, byte r, byte g, byte b)
        {
            int count = list.Count;

            //Random rand = new Random();
            byte[] colorBytes = new byte[3];

            double preStart = 0, preEnd = 0;


            for (int i = 0; i < count; i++)
            {
                TextObject testText = new TextObject(mainContext, x, y, ((TextObj)list[i]).StrText);

                testText.setAnimationTime(myStoryboard, i*2, (i*2)+2);

                
                testText.setFontFamily("HY각헤드라인M");


                list[i].addViewportObject(testText);
                testText.setLibraryObj(list[i]);
                testText.setObjectIDX();


                //testText.AnimationRegist(new OpacityApearAnimation(), myStoryboard);
                //testText.AnimationRegist(new OpacityDisappearAnimation(), myStoryboard);

                testText.AnimationRegist(new FlyAppearAnimation(), myStoryboard);
                //testText.AnimationRegist(new FlyDisAppearAnimation(), myStoryboard);

                //rand.NextBytes(colorBytes);


                Random rand = new Random();
                Color randomColor = Colors.White;
                if (mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).fontColor != null)
                {
                    int num = rand.Next(5);
                    while (num == mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).selectNum)
                    {
                        num = rand.Next(5);
                    }
                    randomColor = mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).fontColor[num];
                }

                testText.setColor(randomColor);

                testText.setColor(randomColor);


                preStart = testText.startTime;
                preEnd = testText.endTime;

                m_rootObject.addObject(testText);

            }
        }

        public void CreateText(TextObj textObj, double x, double y, double start, double end, double scale, byte r, byte g, byte b)
        {
            TextObject testText = new TextObject(mainContext, x, y, textObj.StrText);
            testText.setAnimationTime(myStoryboard, start, end);
            testText.setFontFamily("HY각헤드라인M");
            //testText.AnimationRegist(new OpacityApearAnimation(), myStoryboard);
            //testText.setAnimationTime(myStoryboard, start, end);


            textObj.addViewportObject(testText);
            testText.setLibraryObj(textObj);
            testText.setObjectIDX();


            Random rand = new Random();
            Color randomColor = Colors.White;
            if (mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).fontColor != null)
            {
                int num = rand.Next(5);
                while (num == mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).selectNum)
                {
                    num = rand.Next(5);
                }
                randomColor = mainContext.cameraManager.pageList.ElementAt(mainContext.cameraManager.pageList.Count - 1).fontColor[num];
            }

            testText.setColor(randomColor);



            m_rootObject.addObject(testText);
        }

        public void createPictureObject(ImageObj imgObj, double x, double y, double start, double end)
        {
            PictureObject testText = new PictureObject(mainContext, x, y);



            imgObj.addViewportObject(testText);
            testText.setLibraryObj(imgObj);
            testText.setObjectIDX();


            testText.setAnimationTime(myStoryboard, start, end);

            testText.setImage(imgObj.fileFullPath);

            m_rootObject.addObject(testText);


        }

        public void createRectangleObject(double x, double y, double start, double end)
        {
            RectangleObject testText = new RectangleObject(mainContext, x, y);
            testText.setAnimationTime(myStoryboard, start, end);


            testText.setObjectIDX();

            m_rootObject.addObject(testText);
        }

        public void resetObject()
        {

            CurrentSelectObj = null;


            if (m_rootObject.ObjectList.Count > 0)
            {
                for (int i = 0; i < m_rootObject.ObjectList.Count; i++)
                {

                    (m_rootObject.ObjectList[0] as ViewportObj).DeleteObject(mainContext);
                    (m_rootObject.ObjectList[0] as ViewportObj).LibraryObj.removeViewportObject(m_rootObject.ObjectList[i] as ViewportObj);
                    m_rootObject.ObjectList[0] = null;

                    m_rootObject.ObjectList.RemoveAt(0);
                }


            }
        }
        public void DeleteObject()
        {
            if (CurrentSelectObj == null) return;

            if (m_rootObject.ObjectList.Count > 0)
            {
                for (int i = 0; i < m_rootObject.ObjectList.Count; i++ )
                {
                    if(m_rootObject.ObjectList.ElementAt(i) == CurrentSelectObj)
                    {
                        (m_rootObject.ObjectList[i] as ViewportObj).DeleteObject(mainContext);
                        (m_rootObject.ObjectList[i] as ViewportObj).LibraryObj.removeViewportObject(m_rootObject.ObjectList[i] as ViewportObj);
                        m_rootObject.ObjectList[i] = null;

                        m_rootObject.ObjectList.RemoveAt(i);


                        CurrentSelectObj = null;
                        
                        break;

                    }
                }


            }
        }
        #endregion

        public void objectSetFont(String font)
        {
            if (selectList == null) return;

            for (int i = 0; i < selectList.Count; i++)
            {

                if (selectList[i].ObjectInfo == "TextObject")
                {
                    (selectList[i] as TextObject).setFontFamily(font);
                }
                else if (selectList[i].ObjectInfo == "ParticleObject")
                {
                    (selectList[i] as ParticleObject).setFontFamily(font);
                }

            }

        }
        public void MouseRightDownObject(object sender, MouseButtonEventArgs e)
        {
            foreach (ViewportObj textObject in m_rootObject.ObjectList)
            {

                if (textObject == null) continue;

                String name = (textObject.objectIDX);
                if (sender is Grid) continue;
                if (name.Equals((sender as Viewbox).Name))
                {
                    //mainContext.grid_property.Visibility = Visibility.Visible;
                    break;

                }
            }

            if ((CurrentSelectObj != null) && CurrentSelectObj.isSelect == true)
            {
                Mouse.Capture((sender as Viewbox));
            }
        }


        #region Mouse
        public void MouseDownObject(object sender, MouseButtonEventArgs e)
        {
            foreach (ViewportObj textObject in m_rootObject.ObjectList)
            {

                if (textObject == null) continue;
                String name = (textObject.objectIDX);
                if (name.Equals((sender as Viewbox).Name))
                {
                    if (Keyboard.IsKeyDown(Key.LeftCtrl))
                    {
                        CurrentSelectObj = textObject;
                        selectList.Add(textObject);
                        CurrentSelectObj.selectBox.visibleSelectBox();
                    }
                    else
                    {
                        unSelectObject();
                        CurrentSelectObj = textObject;

                        selectList.Clear();
                        selectList.Add(CurrentSelectObj);
                        
                        CurrentSelectObj.selectBox.visibleSelectBox();
                    }
                    CurrentSelectObj.isSelect = true;
                    CurrentSelectObj.selectObject(mainContext, mainContext.mainViewport.RenderSize,new Point(e.GetPosition(mainContext.mainViewport).X, e.GetPosition(mainContext.mainViewport).Y));

                    break;

                }
            }

            if ((CurrentSelectObj != null) && CurrentSelectObj.isSelect == true)
            {
                Mouse.Capture((sender as Viewbox));
            }
        }
        public void unSelectObject()
        {
            if (CurrentSelectObj != null) CurrentSelectObj.selectBox.InvisibleSelectBox();

            for (int i = 0; i < selectList.Count; i++)
            {
                selectList[i].selectBox.InvisibleSelectBox();
            }
            CurrentSelectObj = null;
        }

        public void MouseUpObject()
        {
            if (CurrentSelectObj == null) return;

            if (CurrentSelectObj.selectBox != null)
            {
                CurrentSelectObj.selectBox.isRotate = false;
                for (int i = 0; i < CurrentSelectObj.selectBox.pointList.Length; i++)
                    CurrentSelectObj.selectBox.pointList[i].isScale = false;
            }
            if (CurrentSelectObj.isSelect)
            {
                CurrentSelectObj.isSelect = false;
                Mouse.Capture(null);

            } 


        }

        public void MouseMoveObject()
        {

            if (CurrentSelectObj == null) return;
            if (selectList != null && CurrentSelectObj.isSelect)
                selectList[selectList.Count-1].setXYZ(mainContext, mainContext.mainViewport.RenderSize, Mouse.GetPosition(mainContext.mainViewport).X, Mouse.GetPosition(mainContext.mainViewport).Y, 0);


            if (CurrentSelectObj.selectBox != null && CurrentSelectObj.isSelect)
            {
                
                CurrentSelectObj.selectBox.setRotate((selectList[selectList.Count - 1] as ViewportObj).degree);
            }



        }
        #endregion

        public void ObjectRotate()
        {
            if (CurrentSelectObj == null) return;
            if (CurrentSelectObj.selectBox != null && CurrentSelectObj.selectBox.isRotate)
            {
                Point touch = new Point(Mouse.GetPosition(mainContext.mainViewport).X, Mouse.GetPosition(mainContext.mainViewport).Y);

                CurrentSelectObj.setRotate(mainContext, getDegree(CurrentSelectObj.selectBox.CenterPoint, touch));

                
                CurrentSelectObj.selectBox.setRotate(getDegree(CurrentSelectObj.selectBox.CenterPoint, touch));
            }
        }

        public void ObjectScale()
        {
            if (CurrentSelectObj == null) return;
            if (CurrentSelectObj.selectBox != null)
            {
                int pointNum = 0;

                if (CurrentSelectObj.selectBox.pointList[1].isScale)
                    pointNum = 0;
                else if (CurrentSelectObj.selectBox.pointList[2].isScale)
                    pointNum = 1;
                else if (CurrentSelectObj.selectBox.pointList[3].isScale)
                    pointNum = 2;
                else if (CurrentSelectObj.selectBox.pointList[4].isScale)
                    pointNum = 3;


                else if (CurrentSelectObj.selectBox.pointList[5].isScale)
                    pointNum = 4;
                else if (CurrentSelectObj.selectBox.pointList[6].isScale)
                    pointNum = 5;
                else if (CurrentSelectObj.selectBox.pointList[7].isScale)
                    pointNum = 6;
                else if (CurrentSelectObj.selectBox.pointList[8].isScale)
                    pointNum = 7;
                else
                    return;

                Point touch = new Point(Mouse.GetPosition(mainContext.mainViewport).X, Mouse.GetPosition(mainContext.mainViewport).Y);
                
                CurrentSelectObj.setScaleXYZ(mainContext, pointNum, touch.X, touch.Y);
            }


        }
        double getDegree(Point center, Point touch)
        {
            double changeX = (touch.X * 2 / mainContext.mainViewport.RenderSize.Width - 1) * (0.4 * mainContext.cameraManager.getPoint3D().Z) + mainContext.cameraManager.getPoint3D().X + mainContext.cameraManager.getTranslateTransform().OffsetX;
            double changeY = (touch.Y * -2 / mainContext.mainViewport.RenderSize.Height + 1) * (0.24 * mainContext.cameraManager.getPoint3D().Z) + mainContext.cameraManager.getPoint3D().Y + mainContext.cameraManager.getTranslateTransform().OffsetY;

            double dx = center.X - changeX;
            double dy = center.Y - changeY;

            double rad = Math.Atan2(dx, dy);
            double degree = -(rad * 180) / 3.14f;


            return degree;
        }

        #region Animation
        public void ObjectDeleteAnimation(int num)
        {

            for (int i = 0; i < selectList.Count; i++)
            {
                (selectList[i] as ParticleObject).DeleteAnimation(myStoryboard, num);
            }
        }

        public void ObjectChangeAnimation(int one, int two)
        {
            if (selectList == null) return;

            for (int i = 0; i < selectList.Count; i++)
            {
                (selectList[i] as ParticleObject).ChangeAnimation(myStoryboard, one, two);
            }
        }

        public void ObjectAnimationRegist(IAnimation animation, int i)
        {
            if (selectList == null) return;


            (selectList[i]).AnimationRegist(animation, myStoryboard);
           
        }
        #endregion

        internal void changeOpacityMask()
        {
            if (selectList == null) return;

            for (int i = 0; i < selectList.Count; i++)
            {
                (selectList[i] as ViewportObj).setMask(mainContext);
            }
        }

        #region StoryBoard

        void myStoryboard_Completed(object sender, EventArgs e)
        {
            myStoryboard.Stop(mainContext);

        }

        void myStoryboard_Changed(object sender, EventArgs e)
        {
            Clock storyboardClock = (Clock)sender;

            if (storyboardClock.CurrentTime != null)
            {
                foreach (ViewportObj textObject in m_rootObject.ObjectList)
                {
                    textObject.ChkObjet(mainContext, storyboardClock.CurrentTime.Value);

                }
                if (mainContext.cameraManager.pageList.Count > 0)
                    (mainContext.cameraManager.pageList[0] as Page).ChkObjet(mainContext, storyboardClock.CurrentTime.Value);
            }

        }
        #endregion

        #region Play

        public void getStoryboard(TimeSpan seekTime)
        {
            foreach (ViewportObj textObject in m_rootObject.ObjectList)
            {
                textObject.ChkObjet(mainContext, seekTime);
            }

            //myStoryboard.Begin(mainContext, true); // if the second parameter is missing or false, it doesn't work
            myStoryboard.Seek(mainContext, seekTime, TimeSeekOrigin.BeginTime);
            myStoryboard.Pause(mainContext); // stop doesn't work

        }
        public void Pause()
        {
            myStoryboard.Pause(mainContext);
        }

        public void Sart()
        {
            if (CurrentSelectObj == null) return;

            if (CurrentSelectObj.selectBox != null)
                CurrentSelectObj.selectBox.InvisibleSelectBox();

            myStoryboard.Stop(mainContext);
            myStoryboard.Begin(mainContext, true);
        }

        public void Skip()
        {
            myStoryboard.SkipToFill(mainContext);
            myStoryboard.Stop(mainContext);
        }

        public void Stop()
        {
            myStoryboard.Stop(mainContext);
        }
        #endregion

        #region XML
        public void GetViewportXML(XmlWriter writer)
        {
            try
            {
                writer.WriteStartElement("ViewportManager");
                {
                    /*
                    writer.WriteStartElement("");
                    {

                    }
                    writer.WriteEndElement();
                     * */
                }
                writer.WriteEndElement();
            }
            catch (Exception e)
            {
                ErrorManager.Instance.RecordError(e);
            }
        }

        public void SetViewportFromXML(XmlReader reader)
        {
            try
            {

            }
            catch
            {

            }
        }

        public void GetPageXML(XmlWriter writer)
        {
            try
            {
                writer.WriteStartElement("PageManager");
                {
                    /*
                    writer.WriteStartElement("");
                    {

                    }
                    writer.WriteEndElement();
                     * */
                }
                writer.WriteEndElement();
            }
            catch (Exception e)
            {
                ErrorManager.Instance.RecordError(e);
            }
        }

        public void SetPageFromXML(XmlReader reader)
        {
            try
            {

            }
            catch
            {

            }
        }


        #endregion

        public void NotifyPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
